home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Atari Mega Archive 1
/
Atari Mega Archive - Volume 1.iso
/
language
/
xlisp_21.zoo
/
xldmem.c
< prev
next >
Wrap
C/C++ Source or Header
|
1990-02-28
|
15KB
|
694 lines
/* xldmem - xlisp dynamic memory management routines */
/* Copyright (c) 1985, by David Michael Betz
All Rights Reserved
Permission is granted for unrestricted non-commercial use */
#include "xlisp.h"
/* node flags */
#define MARK 1
#define LEFT 2
/* macro to compute the size of a segment */
#define segsize(n) (sizeof(SEGMENT)+((n)-1)*sizeof(struct node))
/* external variables */
extern LVAL obarray,s_gcflag,s_gchook,s_unbound,true;
extern LVAL xlenv,xlfenv,xldenv;
extern char buf[];
/* variables local to xldmem.c and xlimage.c */
SEGMENT *segs,*lastseg,*fixseg,*charseg;
int anodes,nsegs,gccalls;
long nnodes,nfree,total;
LVAL fnodes;
/* external procedures */
extern char *malloc();
extern char *calloc();
/* forward declarations */
FORWARD LVAL newnode();
FORWARD unsigned char *stralloc();
FORWARD SEGMENT *newsegment();
/* cons - construct a new cons node */
LVAL cons(x,y)
LVAL x,y;
{
LVAL nnode;
/* get a free node */
if ((nnode = fnodes) == NIL) {
xlstkcheck(2);
xlprotect(x);
xlprotect(y);
findmem();
if ((nnode = fnodes) == NIL)
xlabort("insufficient node space");
xlpop();
xlpop();
}
/* unlink the node from the free list */
fnodes = cdr(nnode);
--nfree;
/* initialize the new node */
nnode->n_type = CONS;
rplaca(nnode,x);
rplacd(nnode,y);
/* return the new node */
return (nnode);
}
/* cvstring - convert a string to a string node */
LVAL cvstring(str)
char *str;
{
LVAL val;
xlsave1(val);
val = newnode(STRING);
val->n_strlen = strlen(str) + 1;
val->n_string = stralloc(getslength(val));
strcpy(getstring(val),str);
xlpop();
return (val);
}
/* newstring - allocate and initialize a new string */
LVAL newstring(size)
int size;
{
LVAL val;
xlsave1(val);
val = newnode(STRING);
val->n_strlen = size;
val->n_string = stralloc(getslength(val));
strcpy(getstring(val),"");
xlpop();
return (val);
}
/* cvsymbol - convert a string to a symbol */
LVAL cvsymbol(pname)
char *pname;
{
LVAL val;
xlsave1(val);
val = newvector(SYMSIZE);
val->n_type = SYMBOL;
setvalue(val,s_unbound);
setfunction(val,s_unbound);
setpname(val,cvstring(pname));
xlpop();
return (val);
}
/* cvsubr - convert a function to a subr or fsubr */
LVAL cvsubr(fcn,type,offset)
LVAL (*fcn)(); int type,offset;
{
LVAL val;
val = newnode(type);
val->n_subr = fcn;
val->n_offset = offset;
return (val);
}
/* cvfile - convert a file pointer to a stream */
LVAL cvfile(fp)
FILE *fp;
{
LVAL val;
val = newnode(STREAM);
setfile(val,fp);
setsavech(val,'\0');
return (val);
}
/* cvfixnum - convert an integer to a fixnum node */
LVAL cvfixnum(n)
FIXTYPE n;
{
LVAL val;
if (n >= SFIXMIN && n <= SFIXMAX)
return (&fixseg->sg_nodes[(int)n-SFIXMIN]);
val = newnode(FIXNUM);
val->n_fixnum = n;
return (val);
}
/* cvflonum - convert a floating point number to a flonum node */
LVAL cvflonum(n)
FLOTYPE n;
{
LVAL val;
val = newnode(FLONUM);
val->n_flonum = n;
return (val);
}
/* cvchar - convert an integer to a character node */
LVAL cvchar(n)
int n;
{
if (n >= CHARMIN && n <= CHARMAX)
return (&charseg->sg_nodes[n-CHARMIN]);
xlerror("character code out of range",cvfixnum((FIXTYPE)n));
}
/* newustream - create a new unnamed stream */
LVAL newustream()
{
LVAL val;
val = newnode(USTREAM);
sethead(val,NIL);
settail(val,NIL);
return (val);
}
/* newobject - allocate and initialize a new object */
LVAL newobject(cls,size)
LVAL cls; int size;
{
LVAL val;
val = newvector(size+1);
val->n_type = OBJECT;
setelement(val,0,cls);
return (val);
}
/* newclosure - allocate and initialize a new closure */
LVAL newclosure(name,type,env,fenv)
LVAL name,type,env,fenv;
{
LVAL val;
val = newvector(CLOSIZE);
val->n_type = CLOSURE;
setname(val,name);
settype(val,type);
setenv(val,env);
setfenv(val,fenv);
return (val);
}
/* newstruct - allocate and initialize a new structure node */
LVAL newstruct(type,size)
LVAL type; int size;
{
LVAL val;
val = newvector(size+1);
val->n_type = STRUCT;
setelement(val,0,type);
return (val);
}
/* newvector - allocate and initialize a new vector node */
LVAL newvector(size)
int size;
{
LVAL vect;
int bsize;
xlsave1(vect);
vect = newnode(VECTOR);
vect->n_vsize = 0;
if (bsize = size * sizeof(LVAL)) {
if ((vect->n_vdata = (LVAL *)calloc(1,bsize)) == NULL) {
findmem();
if ((vect->n_vdata = (LVAL *)calloc(1,bsize)) == NULL)
xlfail("insufficient vector space");
}
vect->n_vsize = size;
total += (long) bsize;
}
xlpop();
return (vect);
}
/* newnode - allocate a new node */
LOCAL LVAL newnode(type)
int type;
{
LVAL nnode;
/* get a free node */
if ((nnode = fnodes) == NIL) {
findmem();
if ((nnode = fnodes) == NIL)
xlabort("insufficient node space");
}
/* unlink the node from the free list */
fnodes = cdr(nnode);
nfree -= 1L;
/* initialize the new node */
nnode->n_type = type;
rplacd(nnode,NIL);
/* return the new node */
return (nnode);
}
/* stralloc - allocate memory for a string adding a byte for the terminator */
LOCAL unsigned char *stralloc(size)
int size;
{
unsigned char *sptr;
/* allocate memory for the string copy */
if ((sptr = (unsigned char *)malloc(size)) == NULL) {
gc();
if ((sptr = (unsigned char *)malloc(size)) == NULL)
xlfail("insufficient string space");
}
total += (long)size;
/* return the new string memory */
return (sptr);
}
/* findmem - find more memory by collecting then expanding */
LOCAL findmem()
{
gc();
if (nfree < (long)anodes)
addseg();
}
/* gc - garbage collect (only called here and in xlimage.c) */
gc()
{
register LVAL **p,*ap,tmp;
char buf[STRMAX+1];
LVAL *newfp,fun;
/* print the start of the gc message */
if (s_gcflag && getvalue(s_gcflag)) {
sprintf(buf,"[ gc: total %ld, ",nnodes);
stdputstr(buf);
}
/* mark the obarray, the argument list and the current environment */
if (obarray)
mark(obarray);
if (xlenv)
mark(xlenv);
if (xlfenv)
mark(xlfenv);
if (xldenv)
mark(xldenv);
/* mark the evaluation stack */
for (p = xlstack; p < xlstktop; ++p)
if (tmp = **p)
mark(tmp);
/* mark the argument stack */
for (ap = xlargstkbase; ap < xlsp; ++ap)
if (tmp = *ap)
mark(tmp);
/* sweep memory collecting all unmarked nodes */
sweep();
/* count the gc call */
++gccalls;
/* call the *gc-hook* if necessary */
if (s_gchook && (fun = getvalue(s_gchook))) {
newfp = xlsp;
pusharg(cvfixnum((FIXTYPE)(newfp - xlfp)));
pusharg(fun);
pusharg(cvfixnum((FIXTYPE)2));
pusharg(cvfixnum((FIXTYPE)nnodes));
pusharg(cvfixnum((FIXTYPE)nfree));
xlfp = newfp;
xlapply(2);
}
/* print the end of the gc message */
if (s_gcflag && getvalue(s_gcflag)) {
sprintf(buf,"%ld free ]\n",nfree);
stdputstr(buf);
}
}
/* mark - mark all accessible nodes */
LOCAL mark(ptr)
LVAL ptr;
{
register LVAL this,prev,tmp;
int type,i,n;
/* initialize */
prev = NIL;
this = ptr;
/* mark this list */
for (;;) {
/* descend as far as we can */
while (!(this->n_flags & MARK))
/* check cons and unnamed stream nodes */
if ((type = ntype(this)) == CONS || type == USTREAM) {
if (tmp = car(this)) {
this->n_flags |= MARK|LEFT;
rplaca(this,prev);
}
else if (tmp = cdr(this)) {
this->n_flags |= MARK;
rplacd(this,prev);
}
else { /* both sides nil */
this->n_flags |= MARK;
break;
}
prev = this; /* step down the branch */
this = tmp;
}
/* mark other node types */
else {
this->n_flags |= MARK;
switch (type) {
case SYMBOL:
case OBJECT:
case VECTOR:
case CLOSURE:
case STRUCT:
for (i = 0, n = getsize(this); --n >= 0; ++i)
if (tmp = getelement(this,i))
mark(tmp);
break;
}
break;
}
/* backup to a point where we can continue descending */
for (